home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectShow / Common / dshowutil.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  15.8 KB  |  619 lines

  1. //------------------------------------------------------------------------------
  2. // File: DShowUtil.cpp
  3. //
  4. // Desc: DirectShow sample code - utility functions.
  5. //
  6. // Copyright (c) 2000-2001 Microsoft Corporation.  All rights reserved.
  7. //------------------------------------------------------------------------------
  8.  
  9. #include "stdafx.h"
  10. #include <atlbase.h>
  11. #include <dshow.h>
  12. #include <mtype.h>
  13. #include <wxdebug.h>
  14. #include <reftime.h>
  15.  
  16. #include "dshowutil.h"
  17.  
  18.  
  19. HRESULT FindRenderer(IGraphBuilder *pGB, const GUID *mediatype, IBaseFilter **ppFilter)
  20. {
  21.     HRESULT hr;
  22.     IEnumFilters *pEnum = NULL;
  23.     IBaseFilter *pFilter = NULL;
  24.     IPin *pPin;
  25.     ULONG ulFetched, ulInPins, ulOutPins;
  26.     BOOL bFound=FALSE;
  27.  
  28.     // Verify graph builder interface
  29.     if (!pGB)
  30.         return E_NOINTERFACE;
  31.  
  32.     // Verify that a media type was passed
  33.     if (!mediatype)
  34.         return E_POINTER;
  35.  
  36.     // Clear the filter pointer in case there is no match
  37.     if (ppFilter)
  38.         *ppFilter = NULL;
  39.  
  40.     // Get filter enumerator
  41.     hr = pGB->EnumFilters(&pEnum);
  42.     if (FAILED(hr))
  43.         return hr;
  44.  
  45.     pEnum->Reset();
  46.  
  47.     // Enumerate all filters in the graph
  48.     while(!bFound && (pEnum->Next(1, &pFilter, &ulFetched) == S_OK))
  49.     {
  50. #ifdef DEBUG
  51.         // Read filter name for debugging purposes
  52.         FILTER_INFO FilterInfo;
  53.         TCHAR szName[256];
  54.     
  55.         hr = pFilter->QueryFilterInfo(&FilterInfo);
  56.         if (SUCCEEDED(hr))
  57.         {
  58.             // Show filter name in debugger
  59. #ifdef UNICODE
  60.             lstrcpy(szName, FilterInfo.achName);
  61. #else
  62.             WideCharToMultiByte(CP_ACP, 0, FilterInfo.achName, -1, szName, 256, 0, 0);
  63. #endif
  64.             FilterInfo.pGraph->Release();
  65.         }       
  66. #endif
  67.  
  68.         // Find a filter with one input and no output pins
  69.         hr = CountFilterPins(pFilter, &ulInPins, &ulOutPins);
  70.         if (FAILED(hr))
  71.             break;
  72.  
  73.         if ((ulInPins == 1) && (ulOutPins == 0))
  74.         {
  75.             // Get the first pin on the filter
  76.             pPin=0;
  77.             pPin = GetInPin(pFilter, 0);
  78.  
  79.             // Read this pin's major media type
  80.             AM_MEDIA_TYPE type={0};
  81.             hr = pPin->ConnectionMediaType(&type);
  82.             if (FAILED(hr))
  83.                 break;
  84.  
  85.             // Is this pin's media type the requested type?
  86.             // If so, then this is the renderer for which we are searching.
  87.             // Copy the interface pointer and return.
  88.             if (type.majortype == *mediatype)
  89.             {
  90.                 // Found our filter
  91.                 *ppFilter = pFilter;
  92.                 bFound = TRUE;;
  93.             }
  94.             // This is not the renderer, so release the interface.
  95.             else
  96.                 pFilter->Release();
  97.  
  98.             // Delete memory allocated by ConnectionMediaType()
  99.             FreeMediaType(type);
  100.         }
  101.         else
  102.         {
  103.             // No match, so release the interface
  104.             pFilter->Release();
  105.         }
  106.     }
  107.  
  108.     pEnum->Release();
  109.     return hr;
  110. }
  111.  
  112. HRESULT FindAudioRenderer(IGraphBuilder *pGB, IBaseFilter **ppFilter)
  113. {
  114.     return FindRenderer(pGB, &MEDIATYPE_Audio, ppFilter);
  115. }
  116.  
  117. HRESULT FindVideoRenderer(IGraphBuilder *pGB, IBaseFilter **ppFilter)
  118. {
  119.     return FindRenderer(pGB, &MEDIATYPE_Video, ppFilter);
  120. }
  121.  
  122. HRESULT CountFilterPins(IBaseFilter *pFilter, ULONG *pulInPins, ULONG *pulOutPins)
  123. {
  124.     HRESULT hr=S_OK;
  125.     IEnumPins *pEnum=0;
  126.     ULONG ulFound;
  127.     IPin *pPin;
  128.  
  129.     // Verify input
  130.     if (!pFilter || !pulInPins || !pulOutPins)
  131.         return E_POINTER;
  132.  
  133.     // Clear number of pins found
  134.     *pulInPins = 0;
  135.     *pulOutPins = 0;
  136.  
  137.     // Get pin enumerator
  138.     hr = pFilter->EnumPins(&pEnum);
  139.     if(FAILED(hr)) 
  140.         return hr;
  141.  
  142.     pEnum->Reset();
  143.  
  144.     // Count every pin on the filter
  145.     while(S_OK == pEnum->Next(1, &pPin, &ulFound))
  146.     {
  147.         PIN_DIRECTION pindir = (PIN_DIRECTION)3;
  148.  
  149.         hr = pPin->QueryDirection(&pindir);
  150.  
  151.         if(pindir == PINDIR_INPUT)
  152.             (*pulInPins)++;
  153.         else
  154.             (*pulOutPins)++;
  155.  
  156.         pPin->Release();
  157.     } 
  158.  
  159.     pEnum->Release();
  160.     return hr;
  161. }
  162.  
  163.  
  164. HRESULT CountTotalFilterPins(IBaseFilter *pFilter, ULONG *pulPins)
  165. {
  166.     HRESULT hr;
  167.     IEnumPins *pEnum=0;
  168.     ULONG ulFound;
  169.     IPin *pPin;
  170.  
  171.     // Verify input
  172.     if (!pFilter || !pulPins)
  173.         return E_POINTER;
  174.  
  175.     // Clear number of pins found
  176.     *pulPins = 0;
  177.  
  178.     // Get pin enumerator
  179.     hr = pFilter->EnumPins(&pEnum);
  180.     if(FAILED(hr)) 
  181.         return hr;
  182.  
  183.     // Count every pin on the filter, ignoring direction
  184.     while(S_OK == pEnum->Next(1, &pPin, &ulFound))
  185.     {
  186.         (*pulPins)++;
  187.         pPin->Release();
  188.     } 
  189.  
  190.     pEnum->Release();
  191.     return hr;
  192. }
  193.  
  194.  
  195. HRESULT GetPin( IBaseFilter * pFilter, PIN_DIRECTION dirrequired, int iNum, IPin **ppPin)
  196. {
  197.     CComPtr< IEnumPins > pEnum;
  198.     *ppPin = NULL;
  199.     HRESULT hr = pFilter->EnumPins(&pEnum);
  200.     if(FAILED(hr)) 
  201.         return hr;
  202.  
  203.     ULONG ulFound;
  204.     IPin *pPin;
  205.     hr = E_FAIL;
  206.  
  207.     while(S_OK == pEnum->Next(1, &pPin, &ulFound))
  208.     {
  209.         PIN_DIRECTION pindir = (PIN_DIRECTION)3;
  210.         pPin->QueryDirection(&pindir);
  211.         if(pindir == dirrequired)
  212.         {
  213.             if(iNum == 0)
  214.             {
  215.                 *ppPin = pPin;
  216.                 // Found requested pin, so clear error
  217.                 hr = S_OK;
  218.                 break;
  219.             }
  220.             iNum--;
  221.         } 
  222.  
  223.         pPin->Release();
  224.     } 
  225.  
  226.     return hr;
  227. }
  228.  
  229.  
  230. IPin * GetInPin( IBaseFilter * pFilter, int Num )
  231. {
  232.     CComPtr< IPin > pComPin;
  233.     GetPin(pFilter, PINDIR_INPUT, Num, &pComPin);
  234.     return pComPin;
  235. }
  236.  
  237.  
  238. IPin * GetOutPin( IBaseFilter * pFilter, int Num )
  239. {
  240.     CComPtr< IPin > pComPin;
  241.     GetPin(pFilter, PINDIR_OUTPUT, Num, &pComPin);
  242.     return pComPin;
  243. }
  244.  
  245.  
  246. HRESULT FindOtherSplitterPin(IPin *pPinIn, GUID guid, int nStream, IPin **ppSplitPin)
  247. {
  248.     if (!ppSplitPin)
  249.         return E_POINTER;
  250.  
  251.     CComPtr< IPin > pPinOut;
  252.     pPinOut = pPinIn;
  253.  
  254.     while(pPinOut)
  255.     {
  256.         PIN_INFO ThisPinInfo;
  257.         pPinOut->QueryPinInfo(&ThisPinInfo);
  258.         if(ThisPinInfo.pFilter) ThisPinInfo.pFilter->Release();
  259.  
  260.         pPinOut = NULL;
  261.         CComPtr< IEnumPins > pEnumPins;
  262.         ThisPinInfo.pFilter->EnumPins(&pEnumPins);
  263.         if(!pEnumPins)
  264.         {
  265.             return NULL;
  266.         }
  267.  
  268.         // look at every pin on the current filter...
  269.         //
  270.         ULONG Fetched = 0;
  271.         while(1)
  272.         {
  273.             CComPtr< IPin > pPin;
  274.             Fetched = 0;
  275.             ASSERT(!pPin); // is it out of scope?
  276.             pEnumPins->Next(1, &pPin, &Fetched);
  277.             if(!Fetched)
  278.             {
  279.                 break;
  280.             }
  281.  
  282.             PIN_INFO pi;
  283.             pPin->QueryPinInfo(&pi);
  284.             if(pi.pFilter) pi.pFilter->Release();
  285.  
  286.             // if it's an input pin...
  287.             //
  288.             if(pi.dir == PINDIR_INPUT)
  289.             {
  290.                 // continue searching upstream from this pin
  291.                 //
  292.                 pPin->ConnectedTo(&pPinOut);
  293.  
  294.                 // a pin that supports the required media type is the
  295.                 // splitter pin we are looking for!  We are done
  296.                 //
  297.             }
  298.             else
  299.             {
  300.                 CComPtr< IEnumMediaTypes > pMediaEnum;
  301.                 pPin->EnumMediaTypes(&pMediaEnum);
  302.                 if(pMediaEnum)
  303.                 {
  304.                     Fetched = 0;
  305.                     AM_MEDIA_TYPE *pMediaType;
  306.                     pMediaEnum->Next(1, &pMediaType, &Fetched);
  307.                     if(Fetched)
  308.                     {
  309.                         if(pMediaType->majortype == guid)
  310.                         {
  311.                             if(nStream-- == 0)
  312.                             {
  313.                                 DeleteMediaType(pMediaType);
  314.                                 *ppSplitPin = pPin;
  315.                                 (*ppSplitPin)->AddRef();
  316.                                 return S_OK;
  317.                             }
  318.                         }
  319.                         DeleteMediaType(pMediaType);
  320.                     }
  321.                 }
  322.             }
  323.  
  324.             // go try the next pin
  325.  
  326.         } // while
  327.     }
  328.     ASSERT(FALSE);
  329.     return E_FAIL;
  330. }
  331.  
  332.  
  333. HRESULT SeekNextFrame( IMediaSeeking * pSeeking, double FPS, long Frame )
  334. {
  335.     // try seeking by frames first
  336.     //
  337.     HRESULT hr = pSeeking->SetTimeFormat(&TIME_FORMAT_FRAME);
  338.     REFERENCE_TIME Pos = 0;
  339.     if(!FAILED(hr))
  340.     {
  341.         pSeeking->GetCurrentPosition(&Pos);
  342.         Pos++;
  343.     }
  344.     else
  345.     {
  346.         // couldn't seek by frames, use Frame and FPS to calculate time
  347.         //
  348.         Pos = REFERENCE_TIME(double( Frame * UNITS ) / FPS);
  349.  
  350.         // add a half-frame to seek to middle of the frame
  351.         //
  352.         Pos += REFERENCE_TIME(double( UNITS ) * 0.5 / FPS);
  353.     }
  354.  
  355.     hr = pSeeking->SetPositions(&Pos, AM_SEEKING_AbsolutePositioning, 
  356.                                 NULL, AM_SEEKING_NoPositioning);
  357.     return hr;
  358.  
  359. }
  360.  
  361. #ifdef DEBUG
  362.     // for debugging purposes
  363.     const INT iMAXLEVELS = 5;                // Maximum debug categories
  364.     extern DWORD m_Levels[iMAXLEVELS];       // Debug level per category
  365. #endif
  366.  
  367.  
  368. void TurnOnDebugDllDebugging( )
  369. {
  370. #ifdef DEBUG
  371.     for(int i = 0 ; i < iMAXLEVELS ; i++)
  372.     {
  373.         m_Levels[i] = 1;
  374.     }
  375. #endif
  376. }
  377.  
  378. void DbgPrint( char * pText )
  379. {
  380.     DbgLog(( LOG_TRACE, 1, "%s", pText ));
  381. }
  382.  
  383. void ErrPrint( char * pText )
  384. {
  385.     printf(pText);
  386.     return;
  387. }
  388.  
  389.  
  390. // Adds a DirectShow filter graph to the Running Object Table,
  391. // allowing GraphEdit to "spy" on a remote filter graph.
  392. HRESULT AddGraphToRot(IUnknown *pUnkGraph, DWORD *pdwRegister) 
  393. {
  394.     IMoniker * pMoniker;
  395.     IRunningObjectTable *pROT;
  396.     WCHAR wsz[128];
  397.     HRESULT hr;
  398.  
  399.     if (FAILED(GetRunningObjectTable(0, &pROT)))
  400.         return E_FAIL;
  401.  
  402.     wsprintfW(wsz, L"FilterGraph %08x pid %08x", (DWORD_PTR)pUnkGraph, 
  403.               GetCurrentProcessId());
  404.  
  405.     hr = CreateItemMoniker(L"!", wsz, &pMoniker);
  406.     if (SUCCEEDED(hr)) 
  407.     {
  408.         hr = pROT->Register(0, pUnkGraph, pMoniker, pdwRegister);
  409.         pMoniker->Release();
  410.     }
  411.     pROT->Release();
  412.     return hr;
  413. }
  414.  
  415. // Removes a filter graph from the Running Object Table
  416. void RemoveGraphFromRot(DWORD pdwRegister)
  417. {
  418.     IRunningObjectTable *pROT;
  419.  
  420.     if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) 
  421.     {
  422.         pROT->Revoke(pdwRegister);
  423.         pROT->Release();
  424.     }
  425. }
  426.  
  427.  
  428. void ShowFilenameByCLSID(REFCLSID clsid, TCHAR *szFilename)
  429. {
  430.     HRESULT hr;
  431.     LPOLESTR strCLSID;
  432.  
  433.     // Convert binary CLSID to a readable version
  434.     hr = StringFromCLSID(clsid, &strCLSID);
  435.     if(SUCCEEDED(hr))
  436.     {
  437.         TCHAR szKey[512];
  438.         CString strQuery(strCLSID);
  439.  
  440.         // Create key name for reading filename registry
  441.         wsprintf(szKey, TEXT("Software\\Classes\\CLSID\\%s\\InprocServer32\0"),
  442.                  strQuery);
  443.  
  444.         // Free memory associated with strCLSID (allocated in StringFromCLSID)
  445.         CoTaskMemFree(strCLSID);
  446.  
  447.         HKEY hkeyFilter=0;
  448.         DWORD dwSize=MAX_PATH;
  449.         BYTE szFile[MAX_PATH];
  450.         int rc=0;
  451.  
  452.         // Open the CLSID key that contains information about the filter
  453.         rc = RegOpenKey(HKEY_LOCAL_MACHINE, szKey, &hkeyFilter);
  454.         if (rc == ERROR_SUCCESS)
  455.         {
  456.             rc = RegQueryValueEx(hkeyFilter, NULL,  // Read (Default) value
  457.                                  NULL, NULL, szFile, &dwSize);
  458.  
  459.             if (rc == ERROR_SUCCESS)
  460.                 wsprintf(szFilename, TEXT("%s"), szFile);
  461.             else
  462.                 wsprintf(szFilename, TEXT("<Unknown>\0"));
  463.  
  464.             rc = RegCloseKey(hkeyFilter);
  465.         }
  466.     }
  467. }
  468.  
  469.  
  470. HRESULT GetFileDurationString(IMediaSeeking *pMS, TCHAR *szDuration)
  471. {
  472.     HRESULT hr;
  473.  
  474.     if (!pMS)
  475.         return E_NOINTERFACE;
  476.     if (!szDuration)
  477.         return E_POINTER;
  478.  
  479.     // Initialize the display in case we can't read the duration
  480.     wsprintf(szDuration, TEXT("<00:00.000>"));
  481.  
  482.     // Is media time supported for this file?
  483.     if (S_OK != pMS->IsFormatSupported(&TIME_FORMAT_MEDIA_TIME))
  484.         return E_NOINTERFACE;
  485.  
  486.     // Read the time format to restore later
  487.     GUID guidOriginalFormat;
  488.     hr = pMS->GetTimeFormat(&guidOriginalFormat);
  489.     if (FAILED(hr))
  490.         return hr;
  491.  
  492.     // Ensure media time format for easy display
  493.     hr = pMS->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME);
  494.     if (FAILED(hr))
  495.         return hr;
  496.  
  497.     // Read the file's duration
  498.     LONGLONG llDuration;
  499.     hr = pMS->GetDuration(&llDuration);
  500.     if (FAILED(hr))
  501.         return hr;
  502.  
  503.     // Return to the original format
  504.     if (guidOriginalFormat != TIME_FORMAT_MEDIA_TIME)
  505.     {
  506.         hr = pMS->SetTimeFormat(&guidOriginalFormat);
  507.         if (FAILED(hr))
  508.             return hr;
  509.     }
  510.  
  511.     // Convert the LONGLONG duration into human-readable format
  512.     unsigned long nTotalMS = (unsigned long) llDuration / 10000; // 100ns -> ms
  513.     int nMS = nTotalMS % 1000;
  514.     int nSeconds = nTotalMS / 1000;
  515.     int nMinutes = nSeconds / 60;
  516.     nSeconds %= 60;
  517.  
  518.     // Update the string
  519.     wsprintf(szDuration, _T("%02dm:%02d.%03ds\0"), nMinutes, nSeconds, nMS);
  520.  
  521.     return hr;
  522. }
  523.  
  524.  
  525. BOOL SupportsPropertyPage(IBaseFilter *pFilter) 
  526. {
  527.     HRESULT hr;
  528.     ISpecifyPropertyPages *pSpecify;
  529.  
  530.     // Discover if this filter contains a property page
  531.     hr = pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pSpecify);
  532.     if (SUCCEEDED(hr)) 
  533.     {
  534.         pSpecify->Release();
  535.         return TRUE;
  536.     }
  537.     else
  538.         return FALSE;
  539. }
  540.  
  541.  
  542. HRESULT ShowFilterPropertyPage(IBaseFilter *pFilter, HWND hwndParent)
  543. {
  544.     HRESULT hr;
  545.     ISpecifyPropertyPages *pSpecify=0;
  546.  
  547.     if (!pFilter)
  548.         return E_NOINTERFACE;
  549.  
  550.     // Discover if this filter contains a property page
  551.     hr = pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pSpecify);
  552.     if (SUCCEEDED(hr)) 
  553.     {
  554.         do 
  555.         {
  556.             FILTER_INFO FilterInfo;
  557.             hr = pFilter->QueryFilterInfo(&FilterInfo);
  558.             if (FAILED(hr))
  559.                 break;
  560.  
  561.             CAUUID caGUID;
  562.             hr = pSpecify->GetPages(&caGUID);
  563.             if (FAILED(hr))
  564.                 break;
  565.  
  566.             pSpecify->Release();
  567.         
  568.             // Display the filter's property page
  569.             OleCreatePropertyFrame(
  570.                 hwndParent,             // Parent window
  571.                 0,                      // x (Reserved)
  572.                 0,                      // y (Reserved)
  573.                 FilterInfo.achName,     // Caption for the dialog box
  574.                 1,                      // Number of filters
  575.                 (IUnknown **)&pFilter,  // Pointer to the filter 
  576.                 caGUID.cElems,          // Number of property pages
  577.                 caGUID.pElems,          // Pointer to property page CLSIDs
  578.                 0,                      // Locale identifier
  579.                 0,                      // Reserved
  580.                 NULL                    // Reserved
  581.             );
  582.             CoTaskMemFree(caGUID.pElems);
  583.             FilterInfo.pGraph->Release(); 
  584.  
  585.         } while(0);
  586.     }
  587.  
  588.     pFilter->Release();
  589.     return hr;
  590. }
  591.  
  592.  
  593. //
  594. // Some hardware decoders and video renderers support stepping media
  595. // frame by frame with the IVideoFrameStep interface.  See the interface
  596. // documentation for more details on frame stepping.
  597. //
  598. BOOL CanFrameStep(IGraphBuilder *pGB)
  599. {
  600.     HRESULT hr;
  601.     IVideoFrameStep* pFS;
  602.  
  603.     hr = pGB->QueryInterface(__uuidof(IVideoFrameStep), (PVOID *)&pFS);
  604.     if (FAILED(hr))
  605.         return FALSE;
  606.  
  607.     // Check if this decoder can step
  608.     hr = pFS->CanStep(0L, NULL); 
  609.  
  610.     pFS->Release();
  611.  
  612.     if (hr == S_OK)
  613.         return TRUE;
  614.     else
  615.         return FALSE;
  616. }
  617.  
  618.  
  619.